//ThreadPool.hpp
#pragma once
#include <iostream>
#include <vector>
#include <queue>
#include <memory>
#include <functional>
#include <unistd.h>
#include "Log.hpp"    // 引入日志
#include "thread.hpp" // 引入线程
#include "mutex.hpp"  // 引入锁
#include "cond.hpp"   // 引入条件变量

namespace ThreadPoolModual
{

    using namespace ThreadModual;
    using namespace CondModul;
    using namespace MutexModel;
    using namespace LogMudule;

    const static int gdefaultthreadnum = 1;

    template <typename T>
    class ThreadPool
    {
    private:
        // 类的成员方法，也可以成为另一个类的回调方法，方便我们继续类级别的互相调用！
        void HandlerTask()
        {
            LOG(LogLevel::INFO) << "entering HandlerTask modual ...";
            while (true)
            {
                LockGuard lock(_mutex);
                T t;
                {
                    // 1. 保证队列安全
                    // 2. 队列中不一定有数据
                    while (_task_queue.empty() && _isrunning)
                    {
                        _waitnum++;
                        _cond.Wait(_mutex);
                        _waitnum--;
                    }
                    // 2.1 如果线程池已经退出了 && 任务队列是空的
                    if (_task_queue.empty() && !_isrunning)
                        break;
                    // 2.2 如果线程池不退出 && 任务队列不是空的
                    // 2.3 如果线程池已经退出 && 任务队列不是空的 --- 处理完所有的任务，然后退出
                    // 3. ⼀定有任务, 处理任务
                    t = _task_queue.front();
                    _task_queue.pop();
                }
                // 4. 处理任务，这个任务属于线程独占的任务
                t();
            }
        }
        //私有实现
        ThreadPool(int threadnum = gdefaultthreadnum) : _threadnum(threadnum),
                                                        _waitnum(0),
                                                        _isrunning(false)
        {
            // 创建线程池
            for (int num = 0; num < _threadnum; num++)
            {
                _threads.emplace_back(std::bind(&ThreadPool::HandlerTask, this));
                LOG(LogLevel::INFO) << "init thread " << _threads.back().Name() << " done";
            }
        }
        // 复制拷贝禁用赋值
        ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;
        ThreadPool(const ThreadPool<T> &) = delete;
    public:
        static ThreadPool<T> *GetInstance()
        {
            if (_instance == nullptr)
            {
                LockGuard lock(_lock);
                if (_instance == nullptr)
                {
                    LOG(LogLevel::INFO) << "单例首次启动";
                    _instance = new ThreadPool<T>();
                    _instance->Start();
                }

            }
            return _instance;
        }

        void Start()
        {
            if (_isrunning)
                return;
            _isrunning = true;
            for (auto &thread : _threads)
            {
                thread.Start();
                LOG(LogLevel::INFO) << "start thread " << thread.Name() << "done";
            }
        }
        void Stop()
        {
            LockGuard lock(_mutex);
            if (_isrunning)
            {
                _isrunning = false;
                if (_waitnum > 0)
                    _cond.NotifyAll();
            }
            LOG(LogLevel::DEBUG) << "threadpool is exitting...";
        }
        void Wait()
        {
            for (auto &thread : _threads)
            {
                thread.Join();
                LOG(LogLevel::INFO) << "Recycling " << thread.Name() << " done";
            }
        }
        void Enqueue(const T &t)
        {
            LockGuard lock(_mutex);
            _task_queue.push(t);
            if (_waitnum > 0)
                _cond.Notify();
        }
        ~ThreadPool()
        {
        }

    private:
        int _threadnum;
        std::vector<Thread> _threads;
        std::queue<T> _task_queue;
        Mutex _mutex;
        Cond _cond;
        int _waitnum;
        bool _isrunning;

        // 添加单例模式
        static ThreadPool<T> *_instance;
        static Mutex _lock;
    };

    template <typename T>
    ThreadPool<T> *ThreadPool<T>::_instance = nullptr;
    template <typename T>
    Mutex ThreadPool<T>::_lock;
}
